﻿using System;
using System.Collections.Generic;
using System.Text;
using Pixysoft.Framework.Noebe;
using System.Data;

namespace Pixysoft.Framework.Security.Tokens
{
    class TokenController
    {
        private static volatile TokenController instance;

        private static object syncRoot = new Object();

        public static TokenController Instance
        {
            get
            {
                if (instance == null)
                {
                    lock (syncRoot)
                    {
                        instance = new TokenController();
                    }
                }

                return instance;

            }
        }


        private string GetTokens(string username, string md5password)
        {
            //2010-02-13 由于多线程问题 可能导致出现相同的token 因此添加时间序列

            string value = username + md5password;

            string token = Pixysoft.Security.MD5.GetMD5(value + Tools.GlobalTimer.Instance.GetUniqueStringSequence());

            return token;
        }


        /// <summary>
        /// 删除所有的token数据和用户数据
        /// </summary>
        public void ShutDown()
        {
            //删除所有的用户数据
            INoebeCommand command = TokenHelper.Instance.GetNoebeManager().NoebeCommand;
            command.SQL = "DELETE FROM SEC_TOKEN_TOKENS";
            command.Execute();
        }

        /// <summary>
        /// 根据token获取一个tokenrow
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        public DataRow GetTokenRow(string token)
        {
            INoebeCommand command = TokenHelper.Instance.GetNoebeManager().NoebeCommand;
            command.SQL = "SELECT * FROM SEC_TOKEN_TOKENS WHERE TOKENCODE = :TOKENCODE";
            command.Parameters.Add("TOKENCODE", token);

            DataTable table = command.ExecuteReader();

            if (table.Rows.Count == 0)
                return null;

            if (table.Rows.Count > 1)
            {
                LoggerHelper.Error("multiple tokens in list." + token);

                return null;
            }

            return table.Rows[0];
        }


        /// <summary>
        /// 注册一个匿名登录用户 登录时间为5分钟
        /// </summary>
        /// <returns></returns>
        public string AnonymousLogin()
        {
            DateTime now = TokenHelper.DateTimeNow;

            string token = GetTokens(TokenHelper.default_anonymous, TokenHelper.default_anonymous);

            DataTable tokentb = TokenHelper.Instance.GetNoebeManager().GetEntity("SEC_TOKEN_TOKENS");
            DataRow tokenrow = tokentb.NewRow();
            tokenrow["TOKENCODE"] = token;
            tokenrow["USERCODE"] = DBNull.Value;
            tokenrow["ISSUPERUSER"] = false;
            tokenrow["STARTDATE"] = TokenHelper.DateTimeNow;
            tokenrow["TIMESPANMINUTES"] = TokenHelper.default_tokendb_TimeOut;
            tokenrow["ENDDATE"] = now.AddMinutes(TokenHelper.default_tokendb_TimeOut);
            tokenrow["ANONYMOUS"] = true;
            tokenrow["CREATEDATE"] = now;
            tokenrow["MODIDATE"] = now;
            tokentb.Rows.Add(tokenrow);

            TokenHelper.Instance.GetNoebeManager().Session.Insert(tokentb);

            return token;
        }
        public string Login(DataRow usrprofileRow)
        {
            return Login(usrprofileRow, TokenHelper.default_tokendb_TimeOut);
        }
        public string Login(DataRow usrprofileRow, int timeoutMins)
        {
            string token = GetTokens(usrprofileRow["USERNAME"].ToString(), usrprofileRow["USERPASSWORD"].ToString());

            DateTime now = TokenHelper.DateTimeNow;

            DataTable tokentb = TokenHelper.Instance.GetNoebeManager().GetEntity("SEC_TOKEN_TOKENS");
            DataRow tokenrow = tokentb.NewRow();
            tokenrow["TOKENCODE"] = token;
            tokenrow["USERCODE"] = usrprofileRow["USERCODE"];
            tokenrow["ISSUPERUSER"] = usrprofileRow["ISSUPERUSER"];
            tokenrow["STARTDATE"] = TokenHelper.DateTimeNow;
            tokenrow["TIMESPANMINUTES"] = timeoutMins;
            tokenrow["ENDDATE"] = now.AddMinutes(timeoutMins);
            tokenrow["ANONYMOUS"] = false;
            tokenrow["CREATEDATE"] = now;
            tokenrow["MODIDATE"] = now;
            tokentb.Rows.Add(tokenrow);

            TokenHelper.Instance.GetNoebeManager().Session.Insert(tokentb);

            return token;
        }


        /// <summary>
        /// 验证token是否有效，如果是匿名，直接返回true，否则就验证时间戳
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        public bool TokenValidate(string token)
        {
            DataRow tokenrow = GetTokenRow(token);

            //如果缓存失效 则进行数据库判断

            return TokenValidate(tokenrow);
        }
        public bool TokenValidate(DataRow tokenrow)
        {
            if (tokenrow == null)
                return false;

            if (IsAnonymous(tokenrow))
                return true;

            DateTime now = TokenHelper.DateTimeNow;

            DateTime tokentime = DateTime.Parse(tokenrow["ENDDATE"].ToString());

            if (tokentime > now)
            {
                return true;
            }

            return false;
        }

        /// <summary>
        /// 延期
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        public bool TokenExtend(string token)
        {
            DateTime now = TokenHelper.DateTimeNow;
            DateTime end = now.AddMinutes(TokenHelper.default_tokendb_TimeOut);

            INoebeCommand command = TokenHelper.Instance.GetNoebeManager().NoebeCommand;
            command.SQL = "UPDATE SEC_TOKEN_TOKENS SET STARTDATE = :STARTDATE,ENDDATE = :ENDDATE,MODIDATE = :MODIDATE WHERE TOKENCODE = :TOKENCODE";
            command.Parameters.Add("STARTDATE", now);
            command.Parameters.Add("ENDDATE", end);
            command.Parameters.Add("MODIDATE", now);
            command.Parameters.Add("TOKENCODE", token);

            return command.Execute() > 0;
        }
        public bool TokenExtend(DataRow tokenrow)
        {
            DateTime now = TokenHelper.DateTimeNow;
            DateTime end = now.AddMinutes(TokenHelper.default_tokendb_TimeOut);

            tokenrow["STARTDATE"] = now;
            tokenrow["ENDDATE"] = end;
            tokenrow["MODIDATE"] = now;

            return TokenHelper.Instance.GetNoebeManager().Session.Update(tokenrow) > 0;
        }


        /// <summary>
        /// 直接删除token
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        public bool TokenRemove(string token)
        {
            INoebeCommand command = TokenHelper.Instance.GetNoebeManager().NoebeCommand;
            command.SQL = "DELETE FROM SEC_TOKEN_TOKENS WHERE TOKENCODE = :TOKENCODE";
            command.Parameters.Add("TOKENCODE", token);
            return command.Execute() > 0;
        }
        public bool TokenRemove(DataRow tokenrow)
        {
            return TokenHelper.Instance.GetNoebeManager().Session.Delete(tokenrow) > 0;
        }


        /// <summary>
        /// 删除过期的token
        /// </summary>
        public bool TokenExpiredRemove()
        {
            DateTime now = TokenHelper.DateTimeNow;
            INoebeCommand command = TokenHelper.Instance.GetNoebeManager().NoebeCommand;
            command.SQL = "DELETE FROM SEC_TOKEN_TOKENS WHERE ENDDATE < :ENDDATE";
            command.Parameters.Add("ENDDATE", now);
            return command.Execute() > 0;
        }


        /// <summary>
        /// 获取数据库token，查看是否匿名
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        public bool IsAnonymous(string token)
        {
            DataRow tokenrow = GetTokenRow(token);

            return IsAnonymous(tokenrow);

        }
        public bool IsAnonymous(DataRow tokenrow)
        {
            if (tokenrow == null)
                return false;

            return bool.Parse(tokenrow["ANONYMOUS"].ToString());
        }
    }
}
